package com.mini.service;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.mini.conditon.AutomatedCondition;
import com.mini.conditon.BusinessChanceMaxSetCondition;
import com.mini.conditon.TeacherCondition;
import com.mini.constant.MqConstants;
import com.mini.constant.RedisKeyConst;
import com.mini.model.BusinessTeacherInfo;
import com.mini.repository.BusinessTeacherInfoRepository;
import com.mini.req.CorpWxInfoREQ;
import com.mini.req.SyncTeacherREQ;
import com.mini.vo.DataCommonMessage;
import com.mini.vo.DataTeacherChanceReceiveLimitVO;
import com.mini.vo.DeptVO;
import com.mini.vo.PageResultVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhangxiaobin
 * @title: BusinessTeacherInfoService
 * @description: TODO
 * @date 2019/10/2716:06
 */
@Service
@Slf4j
public class BusinessTeacherInfoService extends BaseService {

    @Autowired
    private BusinessTeacherWechatInfoService teacherWechatInfoService;

    @Autowired
    private BusinessTeacherInfoRepository businessTeacherInfoRepository;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    public List<BusinessTeacherInfo> findAll() {
        return businessTeacherInfoRepository.findAll();
    }

    public List<BusinessTeacherInfo> findValidAll() {
        return businessTeacherInfoRepository.findByStates(0);
    }

    public List<BusinessTeacherInfo> findByGroupId(Long groupId) {
        List<BusinessTeacherInfo> businessTeacherInfos = businessTeacherInfoRepository.findByGroupIdAndStatesOrderByOrdersAsc(groupId, 0);
        return businessTeacherInfos;
    }

    public List<BusinessTeacherInfo> findByGroupIds(Set<Long> groupIds) {
        return businessTeacherInfoRepository.findByGroupIdIsInAndStatesOrderByOrders(groupIds, 0);
    }


    public List<BusinessTeacherInfo> findByDepId(Long deptId) {
        List<BusinessTeacherInfo> businessTeacherInfos = businessTeacherInfoRepository.findByDeptIdAndStates(deptId, 0);
        return businessTeacherInfos;
    }

    public BusinessTeacherInfo findByTeacherId(Long teacherId) {
        BusinessTeacherInfo one = businessTeacherInfoRepository.findByTeacherId(teacherId);
        return one;
    }

    public void save(BusinessTeacherInfo teacherInfo) {
        businessTeacherInfoRepository.save(teacherInfo);
        removeCacheKey(teacherInfo.getGroupId(), teacherInfo.getTeacherId(), teacherInfo.getDeptId(), teacherInfo.getWorkRoomId());
    }

    @Transactional
    public void saveWechat(BusinessTeacherInfo teacherInfo, SyncTeacherREQ syncTeacherREQ) {
        if (teacherInfo.getStates().intValue() == 1) {
            teacherInfo.setUpdateTime(new Date());
            teacherInfo.setStates(0);
//            teacherInfo.setAddWechatNum(0);
            teacherInfo.setUpdateUser(teacherInfo.getTeacherId());
            businessTeacherInfoRepository.save(teacherInfo);
            removeCacheKey(teacherInfo.getGroupId(), teacherInfo.getTeacherId(), teacherInfo.getDeptId(), teacherInfo.getWorkRoomId());
        }
        teacherWechatInfoService.save(teacherInfo.getTeacherId(),
                teacherInfo.getTeacherName(),
                syncTeacherREQ.getWxId(),
                syncTeacherREQ.getQrUrl(),
                syncTeacherREQ.getTeacherPhoneNum(),
                syncTeacherREQ.getCreateUser(),
                syncTeacherREQ.getWxNewId(),
                syncTeacherREQ.getUseType());
    }

    private void removeCacheKey(Long groupId, Long teacherId, Long deptId, Long workRoomId) {
        if (teacherId != null) {
            redisTemplate.delete(RedisKeyConst.getTeacherInfo(teacherId));
        }
        if (groupId != null) {
            redisTemplate.delete(Sets.newHashSet(RedisKeyConst.getTeacherInfoListGroup(groupId), RedisKeyConst.getTeacherInfoListGroup(groupId, "canuse")));
        }
        if (deptId != null) {
            redisTemplate.delete(RedisKeyConst.getTeacherInfoListDept(deptId));
        }
        if (workRoomId != null) {
            redisTemplate.delete(RedisKeyConst.getTeacherGroupIdsByDeptId(workRoomId));
        }
    }

    public PageResultVO<BusinessTeacherInfo> page(TeacherCondition condition) {
        PageResultVO<BusinessTeacherInfo> resultVO = new PageResultVO<>();
        List<String> orderKeys = new ArrayList<>();
        if (StringUtils.isNotEmpty(condition.getSortColumn())) {
            orderKeys.add(condition.getSortColumn());
        }
        Pageable pageable = null;
        Sort sort = null;
        if (StringUtils.isNotEmpty(condition.getSortType()) && StringUtils.isNotEmpty(condition.getSortColumn())) {
            sort = new Sort(Sort.Direction.valueOf(condition.getSortType()), orderKeys);
        }
        pageable = buildPageRequest(condition.getPageNumber(), condition.getPageSize(), sort);
        Page<BusinessTeacherInfo> page = businessTeacherInfoRepository.findAll(getTeacherSpecification(condition), pageable);
        resultVO.setTotal(page.getTotalElements());
        resultVO.setRows(page.getContent());
        return resultVO;
    }


    public List<BusinessTeacherInfo> page1(BusinessChanceMaxSetCondition condition) {
        PageResultVO<BusinessTeacherInfo> resultVO = new PageResultVO<>();
        List<BusinessTeacherInfo> page = businessTeacherInfoRepository.findAll(getTeacherSpecification1(condition));
        return page;
    }

    private Specification<BusinessTeacherInfo> getTeacherSpecification(TeacherCondition condition) {

        return new Specification<BusinessTeacherInfo>() {
            @Override
            public Predicate toPredicate(Root<BusinessTeacherInfo> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();

                if (condition.getGroupId() != null && 0 != condition.getGroupId()) {
                    predicates.add(cb.equal(root.get("groupId").as(Long.class), condition.getGroupId()));
                }
                if (condition.getDeptId() != null && 0 != condition.getDeptId()) {
                    predicates.add(cb.equal(root.get("deptId").as(Long.class), condition.getDeptId()));
                }
                if (condition.getTeacherId() != null && 0 != condition.getTeacherId()) {
                    predicates.add(cb.equal(root.get("teacherId").as(Long.class), condition.getTeacherId()));
                }
                if (StringUtils.isNotBlank(condition.getTeacherName())) {
                    predicates.add(cb.like(root.get("teacherName").as(String.class), condition.getTeacherName()));
                }
                if (StringUtils.isNotBlank(condition.getGroupIds())) {
                    CriteriaBuilder.In<Long> in = cb.in(root.get("groupId"));
                    List<String> groupIds = Splitter.on(",").omitEmptyStrings().splitToList(condition.getGroupIds());
                    for (String groupId : groupIds) {
                        in.value(Long.valueOf(groupId));
                    }
                    predicates.add(in);
                }
                if (condition.getStates() != null) {
                    predicates.add(cb.equal(root.get("states").as(Integer.class), condition.getStates()));
                }

                if (condition.getWechatNum() != null && 0 == condition.getWechatNum().intValue()) {
                    predicates.add(cb.notEqual(root.get("addWechatNum").as(Integer.class), condition.getWechatNum()));
                }

                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };

    }

    private Specification<BusinessTeacherInfo> getTeacherSpecification1(BusinessChanceMaxSetCondition condition) {

        return new Specification<BusinessTeacherInfo>() {
            @Override
            public Predicate toPredicate(Root<BusinessTeacherInfo> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();

     /*           if(condition.getOgId() != null && condition.getOgId() !=0){
                    queryDeptId.add(condition.getOgId());
                    List<UserVO> t = miniAdminService.operationUserFilter(token,queryDeptId);
                    log.info("param={} result={}",JSONObject.toJSONString(queryDeptId),JSONObject.toJSONString(t));
                    return t;
                }else  if(condition.getOdId() != null && condition.getOdId() != 0){
                    queryDeptId.add(condition.getOdId());
                    List<UserVO> t = miniAdminService.operationUserFilter(token,queryDeptId);
                    log.info("param={} result={}",JSONObject.toJSONString(queryDeptId),JSONObject.toJSONString(t));
                    return t;
                }else  if(condition.getWorkRoomId() != null && condition.getWorkRoomId() != 0){
                    queryDeptId.add(condition.getWorkRoomId());
                    List<UserVO> t = miniAdminService.operationUserFilter(token,queryDeptId);
                    log.info("param={} result={}",JSONObject.toJSONString(queryDeptId),JSONObject.toJSONString(t));
                    return t;
                }else  if(condition.getSkuId() != null && condition.getSkuId() != 0){
                    queryDeptId.add(condition.getSkuId());
                    List<UserVO> t = miniAdminService.operationUserFilter(token,queryDeptId);
                    log.info("param={} result={}",JSONObject.toJSONString(queryDeptId),JSONObject.toJSONString(t));
                    return t;
                }else  if(condition.getDepartmentId() != null && condition.getDepartmentId() != 0){
                    queryDeptId.add(condition.getDepartmentId());
                    List<UserVO> t = miniAdminService.operationUserFilter(token,queryDeptId);
                    log.info("param={} result={}",JSONObject.toJSONString(queryDeptId),JSONObject.toJSONString(t));
                    return t;*/

                if (!CollectionUtils.isEmpty(condition.getUserIdList())) {
                    CriteriaBuilder.In<Long> in = cb.in(root.get("teacherId"));
                    for (Long userId : condition.getUserIdList()) {
                        in.value(userId);
                    }
                    predicates.add(in);
                }

                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };

    }


    @Transactional
    public void saveCorpWechat(BusinessTeacherInfo teacherInfo, CorpWxInfoREQ syncTeacherREQ) {
        Long teacherId = teacherInfo.getTeacherId();
        if (teacherInfo.getStates().intValue() == 1) {
            teacherInfo.setUpdateTime(new Date());
            teacherInfo.setStates(0);
//            teacherInfo.setAddWechatNum(0);
            teacherInfo.setUpdateUser(teacherId);
            businessTeacherInfoRepository.save(teacherInfo);
            removeCacheKey(teacherInfo.getGroupId(), teacherId, teacherInfo.getDeptId(), teacherInfo.getWorkRoomId());
        }
        String teacherName = teacherInfo.getTeacherName();
        teacherWechatInfoService.saveCorpWx(teacherId, teacherName, syncTeacherREQ);
    }

    @Transactional
    public void updateTeacherOpenOrClose(Long teacherId, Integer useState, Long groupId, Long deptId, Long workRoomId) {
        businessTeacherInfoRepository.updateTeacherPbStates(teacherId, useState);
        removeCacheKey(groupId, teacherId, deptId, workRoomId);

    }

    /**
     * 批量设置老师的排班状态
     *
     * @param teacherIds
     * @param operationType
     */
    @Transactional
    public void batchUpdateTeacherOpenOrClose(List<Long> teacherIds, String operationType) {
        Integer useState = 0;
        if ("open".equalsIgnoreCase(operationType)) {
            useState = 0;
        }
        if ("close".equalsIgnoreCase(operationType)) {
            useState = 1;
        }
        businessTeacherInfoRepository.batchUpdateTeacherPbStates(teacherIds, useState);
        for (Long teacherId : teacherIds) {
            String teacherInfoKey = RedisKeyConst.getTeacherInfo(teacherId);
            redisTemplate.delete(teacherInfoKey);
        }
    }

    public void updateAddWechatNum(Long teacherId,Integer addWechatNum){
        businessTeacherInfoRepository.updateAddWechatNum(teacherId,addWechatNum);
        redisTemplate.delete(RedisKeyConst.getTeacherInfo(teacherId));
        synDataAddWechatNum( teacherId, addWechatNum);
    }
    public void synDataAddWechatNum(Long teacherId,Integer addWechatNum){
        DataTeacherChanceReceiveLimitVO teacherChanceReceiveLimitVO = new DataTeacherChanceReceiveLimitVO();
        teacherChanceReceiveLimitVO.setTeacherId(teacherId);
        teacherChanceReceiveLimitVO.setCountDate(new Date());
        teacherChanceReceiveLimitVO.setReceiveLimit(addWechatNum);

        DataCommonMessage commonMessage = new DataCommonMessage();
        commonMessage.setMsgType(DataCommonMessage.MsgType.user_receive_limit.name());
        commonMessage.setData(JSON.toJSONString(teacherChanceReceiveLimitVO));

        CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(MqConstants.EXCHANGE_DATA, MqConstants.ROUTE_KEY_COMMON, commonMessage, a -> {
            a.getMessageProperties().setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN);
            return a;
        }, correlationId);
    }
    public void synDataAddWechatNumALl(){
        Pageable pageable = new PageRequest(0, 100);
        Page<BusinessTeacherInfo> page =null;
        do {
            page = businessTeacherInfoRepository.findAll(pageable);
            pageable = page.nextPageable();
            for (BusinessTeacherInfo businessTeacherInfo : page.getContent()) {
                synDataAddWechatNum( businessTeacherInfo.getTeacherId(), businessTeacherInfo.getAddWechatNum());
            }
        }while (page.hasNext());
    }


    /**
     * 分页获取数据-分配排班新增
     *
     * @param condition
     * @return
     */
    public List<BusinessTeacherInfo> getTeachers(AutomatedCondition condition) {

        Specification<BusinessTeacherInfo> specification = new Specification<BusinessTeacherInfo>() {
            @Override
            public Predicate toPredicate(Root<BusinessTeacherInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();

                if (!CollectionUtils.isEmpty(condition.getOrgIds())) {
                    //根据组织ID获取运营组信息
                    List<DeptVO> deptVOList = groupIdsInfo(condition.getOrgIds(), condition.getUserId());

                    if (!CollectionUtils.isEmpty(deptVOList)) {
                        List<Long> deptIds = deptVOList.stream().map(DeptVO::getId).collect(Collectors.toList());
                        CriteriaBuilder.In<Long> in = criteriaBuilder.in(root.get("groupId"));
                        deptIds.stream().forEach(o -> in.value(o));
                        predicates.add(in);
                    }
                }
                if (!CollectionUtils.isEmpty(condition.getTeacherIds())) {
                    CriteriaBuilder.In<Long> in = criteriaBuilder.in(root.get("teacherId"));
                    condition.getTeacherIds().forEach(o -> in.value(o));
                    predicates.add(in);
                }
                predicates.add(criteriaBuilder.equal(root.get("states").as(Integer.class), 0));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };

        return businessTeacherInfoRepository.findAll(specification);
    }


    /**
     * 查询某个工作室的组ids
     *
     * @param deptIds
     * @return
     */
    public List<Long> findByDeptIdsGroupByGroupId(String deptIds) {
        List<Long> listIds = Arrays.asList(deptIds.split(",")).stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        if (listIds != null && listIds.size() > 0) {
            List<Long> allGroupIds = new ArrayList<>();
            for (Long deptId : listIds) {
                String teacherGroupIdsByDeptIdKey = RedisKeyConst.getTeacherGroupIdsByDeptId(deptId);
                Object o = redisTemplate.opsForValue().get(teacherGroupIdsByDeptIdKey);
                List<Long> groupIds;
                if (o == null) {
                    groupIds = businessTeacherInfoRepository.findGroupIdsByDeptId(deptId);
                    redisTemplate.opsForValue().set(teacherGroupIdsByDeptIdKey, groupIds, 60, TimeUnit.DAYS);
                } else {
                    groupIds = (List<Long>) o;
                }
                allGroupIds.addAll(groupIds);
            }
            return allGroupIds;
        }
        return null;
    }
}

